﻿using System.Collections.Generic;
using System.ServiceModel;
using System.Threading;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using System.Workflow.Runtime.Tracking;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using YakShaver.Contract;
using YakShaver.YakServer;
using System.Reflection;
using System.Windows.Forms;
using System.Net.Mail;
using YakShaver.Tests.DummyObjects;
namespace YakShaver.Tests
{
    /// <summary>
    /// Summary description for CodePlexIntegrationTests
    /// </summary>
    [TestClass]
    public class CodePlexIntegrationTests : IntegrationTestBase
    {
        public CodePlexIntegrationTests() : base(true, true)
        {
            //
            // TODO: Add constructor logic here
            //
        }

     
        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            
            IntegrationTestBase.MyClassInitialize(testContext);
        }
        
        // Use ClassCleanup to run code after all tests in a class have run
        [ClassCleanup()]
        public static void ClassCleanup() {
        //ghetto way of doing this
            IntegrationTestBase.MyClassCleanup();
        }
        //
        // Use TestInitialize to run code before running each test 
        [TestInitialize()]
        public void MyTestInitialize()
        {
            DataExchangeService = new ExternalDataExchangeService();
            WorkflowEngine.AddService(DataExchangeService);
        }
        //
        // Use TestCleanup to run code after each test has run
        [TestCleanup()]
        public void MyTestCleanup()
        {
            // tear down any services in case an assert failed or other exception was thrown
            ExternalDataExchangeService service = DataExchangeService;
            UnitTestHelper.TestCleanup(ref service);
            WorkflowEngine.RemoveService(
                WorkflowEngine.GetService<ExternalDataExchangeService>());
            DataExchangeService = null;
        }
        //
        #endregion
        
        private AutoResetEvent resetEvent;

       
        private void TearDownCodePlexnotificationServiceServices()
        {
            INotificationService notificationService =  (INotificationService)DataExchangeService.GetService(typeof(INotificationService));
            IAnalysisService analysisService = (IAnalysisService) DataExchangeService.GetService(typeof(IAnalysisService));
            IWorkItemProviderService providerService = (IWorkItemProviderService)DataExchangeService.GetService(typeof(IWorkItemProviderService));

            DataExchangeService.RemoveService(notificationService);
            DataExchangeService.RemoveService(analysisService);
            DataExchangeService.RemoveService(providerService);
        }

       // [TestMethod, TestProperty("Category", @"CodePlex\Integration\NotificationService")]
        public void TestCodePlexNotificationService()
        {
            YakShaver.CodePlex.CodePlexNotificationService notificationService = new YakShaver.CodePlex.CodePlexNotificationService(UnitTestHelper.GetSmtpClient(TestContext));
            IAnalysisService analysisService = new IAnalysisDummyService();
            // still using the dummy services because we are grunuarlly testing the notification srevice in the workflow

        }

        [TestMethod, TestProperty("Category", @"CodePlex\Integration\NotificationServiceTests")]
        public void TestHandleInterventionNeeded()
        {

            YakShaver.CodePlex.CodePlexNotificationService notificationService = new YakShaver.CodePlex.CodePlexNotificationService(UnitTestHelper.GetSmtpClient(TestContext));
            IAnalysisService analysisService = new IAnalysisDummyService();
            IWorkItemProviderService providerService = new YakShaver.CodePlex.CodePlexWorkItemService();

            DataExchangeService.AddService(notificationService);
            DataExchangeService.AddService(analysisService);
            DataExchangeService.AddService(providerService);

            
            IWorkItemDataContract dataContract = new WorkItemDataContractDummyObject();
           
            AutoResetEvent cpResetEvent = new AutoResetEvent(false);
            Dictionary<string, object> namedParameters = new Dictionary<string, object>();
            YakShaverWorkItem workItem = null;
            
            namedParameters.Add("WorkItemDataContract", dataContract);
           

            int notifyCount = 0;

            // created here because we are using delegates + anonymous methods instead of fully defined methods.
            WorkflowInstance workflowInstance = WorkflowEngine.CreateWorkflow(typeof(WorkItemEntryWorkflow), namedParameters);

            #region Handle Workflow Runtime Events
           
            WorkflowEngine.WorkflowPersisted += delegate(object sender, WorkflowEventArgs args)
            {
                if (args.WorkflowInstance.InstanceId == workflowInstance.InstanceId)
                {
                    SqlTrackingQuery sqlQuery = new SqlTrackingQuery(sqlTrackingConnectionString);
                    SqlTrackingWorkflowInstance sqlQueryInstance = null;
                    if (sqlQuery.TryGetWorkflow(args.WorkflowInstance.InstanceId, out sqlQueryInstance))
                    {
                        foreach (UserTrackingRecord trackingRecord in sqlQueryInstance.UserEvents)
                        {
                            if (trackingRecord.UserDataKey.Equals("NotifyCount"))
                                notifyCount = (int)trackingRecord.UserData;
                            if (trackingRecord.UserDataKey.Equals("WorkItem"))
                                workItem = (YakShaverWorkItem)trackingRecord.UserData;
                        }
                    }
                }
                return;
            };

            bool workflowCompleted = false;
            WorkflowEngine.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs args)
            {
                if (args.WorkflowInstance.InstanceId == workflowInstance.InstanceId)
                {
                    workflowCompleted = true;
                    cpResetEvent.Set();
                }
            };

            #endregion

            workflowInstance.Start();

          //  cpResetEvent.WaitOne(new System.TimeSpan(0, 0, 0, 45), true);

            Thread.Sleep(5000);
            //idled.. we should be able to fire an event at it.

            //workflowInstance.Load();
            IWorkItemDataContract modifiedDataContract = new WorkItemDataContractDummyObject();
            modifiedDataContract.PageId = "/home/test2.aspx";
            modifiedDataContract.WorkItemImpactType = WorkItemImpactType.Medium;
            modifiedDataContract.WorkItemType = WorkItemType.Issue;

            workflowInstance = WorkflowEngine.GetWorkflow(workflowInstance.InstanceId);

          
            notificationService.ModifyWorkItem(workflowInstance.InstanceId, modifiedDataContract);

            cpResetEvent.WaitOne(new System.TimeSpan(0, 0, 0, 30), true);

            //resetEvent.WaitOne(new System.TimeSpan(0, 0, 0, 45), true);


            Assert.IsTrue(workflowCompleted);
            Assert.IsTrue(notifyCount > 0);

           // TearDownCodePlexnotificationServiceServices();
     
        }

        [TestMethod, TestProperty("Category", @"CodePlex\Integration\NotificationServiceTests")]
        public void TestSubmitAndNeedInterventionMultipleNotification()
        {


            YakShaver.CodePlex.CodePlexNotificationService notificationService = new YakShaver.CodePlex.CodePlexNotificationService(UnitTestHelper.GetSmtpClient(TestContext));
            IAnalysisService analysisService = new IAnalysisDummyService();
            IWorkItemProviderService providerService = new IWorkItemDummyService();
            DataExchangeService.AddService(notificationService);
            DataExchangeService.AddService(analysisService);
            DataExchangeService.AddService(providerService);

            resetEvent = new AutoResetEvent(false);
            IWorkItemDataContract dataContract = new WorkItemDataContractDummyObject();
            Dictionary<string, object> namedParameters = new Dictionary<string, object>();
            System.TimeSpan NotificationCycleDelay = new System.TimeSpan(0, 0, 10);
            namedParameters.Add("WorkItemDataContract", dataContract);
            namedParameters.Add("NotificationCycleDelay", NotificationCycleDelay);


            YakShaverWorkItem workItem = null;

            int notifyCount = 0;

            // created here because we are using delegates + anonymous methods instead of fully defined methods.
            WorkflowInstance workflowInstance = WorkflowEngine.CreateWorkflow(typeof(WorkItemEntryWorkflow), namedParameters);

            #region Handle Workflow Runtime Events
            WorkflowEngine.WorkflowIdled += delegate(object sender, WorkflowEventArgs args)
            {

                args.WorkflowInstance.Unload(); // unlead to see if we keep persistence.


            };
            WorkflowEngine.WorkflowPersisted += delegate(object sender, WorkflowEventArgs args)
            {
                if (args.WorkflowInstance.InstanceId == workflowInstance.InstanceId)
                {
                    SqlTrackingQuery sqlQuery = new SqlTrackingQuery(sqlTrackingConnectionString);
                    SqlTrackingWorkflowInstance sqlQueryInstance = null;
                    if (sqlQuery.TryGetWorkflow(args.WorkflowInstance.InstanceId, out sqlQueryInstance))
                    {
                        foreach (UserTrackingRecord trackingRecord in sqlQueryInstance.UserEvents)
                        {
                            if (trackingRecord.UserDataKey.Equals("NotifyCount"))
                                notifyCount = (int)trackingRecord.UserData;
                            if (trackingRecord.UserDataKey.Equals("WorkItem"))
                                workItem = (YakShaverWorkItem)trackingRecord.UserData;
                        }
                    }
                }
                //    if (notifyCount > 0)
                //      resetEvent.Set();
                return;
            };
            #endregion

            workflowInstance.Start();

            resetEvent.WaitOne(NotificationCycleDelay.Add(NotificationCycleDelay), true);


            Assert.IsTrue((int)notifyCount >= 2, "Expected: {0} Actual: {1}", 2, notifyCount);
            Assert.IsNotNull(workItem);
            Assert.IsTrue(workItem.Status == WorkItemSubmissionStatus.NeedIntervention, "Expected Ready, Received: " + workItem.Status);
            Assert.IsTrue(workItem.WorkItemImpactType == WorkItemImpactType.Unknown, string.Format("Expected Unknown for WorkItemImpactType Received: {0} ", workItem.WorkItemImpactType));
            Assert.IsTrue(workItem.WorkItemType == WorkItemType.Unknown, "Expected Unknown for WorkItemType");


            //TearDownCodePlexnotificationServiceServices();
        }
        [TestMethod, TestProperty("Category", @"CodePlex\Integration\NotificationServiceTests")]
        public void TestSubmitAndNeedIntervention()
        {

            YakShaver.CodePlex.CodePlexNotificationService notificationService = new YakShaver.CodePlex.CodePlexNotificationService(UnitTestHelper.GetSmtpClient(TestContext));
            IAnalysisService analysisService = new IAnalysisDummyService();
            IWorkItemProviderService providerService = new IWorkItemDummyService();
            DataExchangeService.AddService(notificationService);
            DataExchangeService.AddService(analysisService);
            DataExchangeService.AddService(providerService);
         
            resetEvent = new AutoResetEvent(false);
            IWorkItemDataContract dataContract = new WorkItemDataContractDummyObject();
            Dictionary<string, object> namedParameters = new Dictionary<string,object>();
            namedParameters.Add("WorkItemDataContract", dataContract);
            YakShaverWorkItem workItem = null;
            
            int notifyCount = 0;

            // created here because we are using delegates + anonymous methods instead of fully defined methods.
            WorkflowInstance workflowInstance = WorkflowEngine.CreateWorkflow(typeof(WorkItemEntryWorkflow), namedParameters);

            #region Handle Workflow Runtime Events
            WorkflowEngine.WorkflowIdled += delegate(object sender, WorkflowEventArgs args)
            {

              args.WorkflowInstance.Unload(); // unlead to see if we keep persistence.
            
               
            };
            WorkflowEngine.WorkflowPersisted += delegate(object sender, WorkflowEventArgs args) 
            {
                if (args.WorkflowInstance.InstanceId == workflowInstance.InstanceId)
                {
                    SqlTrackingQuery sqlQuery = new SqlTrackingQuery(sqlTrackingConnectionString);
                    SqlTrackingWorkflowInstance sqlQueryInstance = null;
                    if (sqlQuery.TryGetWorkflow(args.WorkflowInstance.InstanceId, out sqlQueryInstance))
                    {
                        foreach (UserTrackingRecord trackingRecord in sqlQueryInstance.UserEvents)
                        {
                            if (trackingRecord.UserDataKey.Equals("NotifyCount"))
                                notifyCount = (int)trackingRecord.UserData;
                            if (trackingRecord.UserDataKey.Equals("WorkItem"))
                                workItem = (YakShaverWorkItem)trackingRecord.UserData;
                        }
                    }
                }
            //    if (notifyCount > 0)
              //      resetEvent.Set();
                return;  
            };
            #endregion

            workflowInstance.Start();
           
            resetEvent.WaitOne(new System.TimeSpan(0, 0,0,45),true);
           
            
             Assert.IsTrue((int)notifyCount == 1, "Expected: {0} Actual: {1}", 1,notifyCount );
             Assert.IsNotNull(workItem);
             Assert.IsTrue(workItem.Status == WorkItemSubmissionStatus.NeedIntervention, "Expected Ready, Received: " + workItem.Status);
             Assert.IsTrue(workItem.WorkItemImpactType == WorkItemImpactType.Unknown, string.Format("Expected Unknown for WorkItemImpactType Received: {0} ", workItem.WorkItemImpactType));
             Assert.IsTrue(workItem.WorkItemType == WorkItemType.Unknown, "Expected Unknown for WorkItemType");


           //  TearDownCodePlexnotificationServiceServices();
        }

       
    }
}
